.text
// 实现函数：void switch_to(long prev, long next);
// 所以rdi=当前任务的tcb, rsi=目标任务的tcb, 
// rsp是前一个任务的堆栈，rsp指向的内容就返回地址的rip。
// 我们要做的是先保存前一个任务的CPU状态到TCB，然后把下一个任务的TCB恢复到CPU上。
.global switch_to
switch_to:
	// 保存前一个任务的TCB
	test %rdi, %rdi                // 检查rdi的值是否为0
	je 1f                          // rdi为0不用保存，跳到后面1的位置
	mov %rsp, 0(%rdi)              // 先保存堆栈指针，马上要用
	lea 8*17(%rdi), %rsp           // 堆栈指针移到TCB rflags的位置
	pushfq                         // 保存rflags
	push %r15                      // 保存剩余的寄存器
	push %r14
	push %r13
	push %r12
	push %r11
	push %r10
	push %r9
	push %r8
	push %rbp
	push %rdi
	push %rsi
	push %rdx
	push %rcx
	push %rbx
	push %rax

1:      lea 8(%rsi), %rsp             // 堆栈指针移动到TCB rax的位置
	pop %rax                      // 恢复所有寄存器
	pop %rbx
	pop %rcx
	pop %rdx
	pop %rsi
	pop %rdi
	pop %rbp
	pop %r8
	pop %r9
	pop %r10
	pop %r11
	pop %r12
	pop %r13
	pop %r14
	pop %r15
	popfq

	// 现在rdi是当时切换的TCB
	mov 0(%rdi), %rsp              // 恢复堆栈
	ret                            // 当时的堆栈中有返回地址，直接ret

// 这是新版本gnu ld需要的安全特性，其实我们的例子不需要，加上避免编译告警而已。
.section .note.GNU-stack,"",@progbits
